////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	MathPlane3D.cpp
//  MathLib
//
//  Created by Gregory Maks on 8/14/09.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "Math.h"



void Plane3D::ctor()
{
	normal.ctor();
	distance = 0;
}

Plane3D::Plane3D ()
{
	ctor();
}

Plane3D::Plane3D (const Plane3D &aPlane)
{
	normal = aPlane.normal;
	distance = aPlane.distance;
}

Plane3D::Plane3D (Vector4 &aNormal, floatType aDistance)
{
	normal = aNormal;
	distance = aDistance;
}

floatType Plane3D::GetSignedDistance (Vector4 &aPoint)
{
	return aPoint.DotProduct(normal) + distance;
}

void Plane3D::Normalize()
{
	floatType inv_mag = 1.0f / normal.Length();
	
	normal.x *= inv_mag;
	normal.y *= inv_mag;
	normal.z *= inv_mag;
	distance *= inv_mag;
}

PlaneClassification Plane3D::GetPointVsPlaneClassification (Vector4 &aPoint)
{
	floatType signedDist = GetSignedDistance(aPoint);
	if (signedDist > 0.0)
		return PlaneClassification_Front;
	else if (signedDist < 0.0)
		return PlaneClassification_Back;
	else 
		return PlaneClassification_Intersects;
}

PlaneClassification Plane3D::GetRectVsPlaneClassification (Rect3D &aRect)
{
	Vector4 minPoint, maxPoint;
	
	// x
	if (normal.x > 0.0f)
	{
		minPoint.x = aRect.p0.x;
		maxPoint.x = aRect.p1.x;
	}
	else if (normal.x < 0.0f)
	{
		minPoint.x = aRect.p1.x;
		maxPoint.x = aRect.p0.x;
	}
	else
	{
		minPoint.x = 0;
		maxPoint.x = 0;
	}
	// y
	if (normal.y > 0.0f)
	{
		minPoint.y = aRect.p0.y;
		maxPoint.y = aRect.p1.y;
	}
	else if (normal.y < 0.0f)
	{
		minPoint.y = aRect.p1.y;
		maxPoint.y = aRect.p0.y;
	}
	else
	{
		minPoint.y = 0;
		maxPoint.y = 0;
	}
	// z
	if (normal.z > 0.0f)
	{
		minPoint.z = aRect.p0.z;
		maxPoint.z = aRect.p1.z;
	}
	else if (normal.z < 0.0f)
	{
		minPoint.z = aRect.p1.z;
		maxPoint.z = aRect.p0.z;
	}
	else
	{
		minPoint.z = 0;
		maxPoint.z = 0;
	}
	
	float dmin = GetSignedDistance(minPoint);
	float dmax = GetSignedDistance(maxPoint);
	
	if (dmin * dmax <= 0.0f)
	{
		return PlaneClassification_Intersects;
	}
	else if (dmin > 0.0f)
	{
		return PlaneClassification_Front;
	}
	return PlaneClassification_Back;
}

PlaneClassification Plane3D::GetQuadVsPlaneClassification (QuadPoly3D &aQuad)
{
	PlaneClassification clasf;
	for (int i=0; i<4; i++)
	{
		float dist = GetSignedDistance(aQuad.pt[i]);
		if (i == 0)
		{
			if (dist > 0) clasf = PlaneClassification_Front;
			else if (dist < 0) clasf = PlaneClassification_Back;
			else {
				clasf = PlaneClassification_Intersects;
				break;
			}
		}
		else
		{
			if ((dist > 0 && clasf == PlaneClassification_Back) ||
				(dist < 0 && clasf == PlaneClassification_Front) ||
				dist == 0) 
			{
				clasf = PlaneClassification_Intersects;
				break;
			}
		}
	}
	return clasf;
}
















